require "LevelHelper.Helpers.LHHelpers"
--------------------------------------------------------------------------------

--notifications
LHAnimationHasEndedGlobalNotification = "LHAnimationHasEndedGlobalNotification"
LHAnimationFrameGlobalNotification = "LHAnimationFrameGlobalNotification"

LHAnimationHasEndedPerSpriteNotification = "LHAnimationHasEndedPerSpriteNotification"
LHAnimationFramePerSpriteNotification = "LHAnimationFramePerSpriteNotification"


LHAnimationFrameInfo = {}
function LHAnimationFrameInfo:frameWithDictionary(frmInfo, giderosTexture)

	if(frmInfo == nil)then
		print("ERROR: Frame info is nil.");
		return nil;
	end
		
	local object = {lhDelayPerUnit = frmInfo:floatForKey("delayPerUnit"),
					lhOffset = frmInfo:pointForKey("offset"),
					lhNotifications = LHDictionary:initWithDictionary(frmInfo:dictForKey("notifications")),
					lhFrameName = frmInfo:stringForKey("spriteframe"),
					lhRect = frmInfo:rectForKey("Frame"),
					lhFrameOffset = frmInfo:pointForKey("TextureOffset"),
					lhRectIsRotated= frmInfo:boolForKey("IsRotated"),
					lhFrameSize = frmInfo:sizeForKey("SpriteSize"),
					
					}
		
	local region = TextureRegion.new(giderosTexture, object.lhRect.origin.x, object.lhRect.origin.y, object.lhRect.size.width, object.lhRect.size.height);
	object.giderosSpriteFrame = Bitmap.new(region)
	object.giderosSpriteFrame:setAnchorPoint(0.5, 0.5);
	
	setmetatable(object, { __index = LHAnimationFrameInfo })  -- Inheritance	
	return object
end
--------------------------------------------------------------------------------
function LHAnimationFrameInfo:removeSelf()
	
	--print("LHAnimationFrameInfo removeSelf");
	
	self.lhDelayPerUnit = nil;
	self.lhOffset = nil;
	self.lhNotifications:removeSelf();
	self.lhNotification = nil;
	self.lhRect = nil;
	self.lhFrameOffset = nil;
	self.lhRectIsRotated = nil;
	self.lhFrameSize = nil;
	self = nil;
end

--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------

LHAnimationNode = Core.class(Sprite)
function LHAnimationNode:animationWithDictionary(animInfo) --returns a display object
	
	if(animInfo == nil)then
		print("ERROR: Animation info is nil. Probably animation could not be found.");
		print("ERROR: Probably SpriteHelper document where this animation was created is in older format. Open it with latest version of SpriteHelper and re-save it.");
		return nil;
	end
	
	self.lhUniqueName = animInfo:stringForKey("UniqueName")
	self.lhSheetName = animInfo:stringForKey("SheetName")
	self.lhSheetImage= animInfo:stringForKey("SheetImage");
	self.lhRestoreOriginalFrame = animInfo:boolForKey("RestoreOriginalFrame")
	self.lhRepetitions = animInfo:intForKey("Repetitions")
	self.lhDelayPerUnit = animInfo:floatForKey("DelayPerUnit")
	self.lhLoop = animInfo:boolForKey("Loop")
	self.lhAnimAtStart = animInfo:boolForKey("StartAtLaunch")
	self.coronaSprite = nil --this needs to be assigned after we create the sprite
	self.repetitionsPerformed = 0
	self.time = 0.0
	self.currentFrame = 1
	self.previousFrame = 1
	self.paused = true
	self.elapsedFrameTime = 0.0
	self.lastEventTime = -1
	self.lhFrames = {}

	self.giderosTexture = Texture.new(imageFileWithFolder(self.lhSheetImage))
	local framesInfo = animInfo:arrayForKey("Frames");
	for i=1, framesInfo:count() do
		
		local frmInfo = framesInfo:dictAtIndex(i);
		self.lhFrames[#self.lhFrames+1] = LHAnimationFrameInfo:frameWithDictionary(frmInfo, self.giderosTexture );
	
	end
	
end
--------------------------------------------------------------------------------
function LHAnimationNode:frameTableFromSheetImageOptionsBasedOnNames(options)

	local frame = {};
	
	for i =1, #self.lhFrames do
	
		local animFrmName = self.lhFrames[i].lhFrameName;
		
		for j = 1, #options.frames do
			local optionName = options.frames[j].spriteName;	
			
			if(animFrmName == optionName)then
				frame[#frame+1] = j;
			end
		end	
	end
	
	return frame;
end
--------------------------------------------------------------------------------
function LHAnimationNode:removeSelf()

	--print("LHAnimationNode removeSelf");

	--self:removeEventListener(Event.ENTER_FRAME, self.enterFrame, self)

	self:removeEnterFrameEvent()
	--Runtime:removeEventListener( "enterFrame", self )

	self.lhUniqueName = nil;
	self.lhSheetName = nil;
	self.lhSheetImage= nil;
	self.lhRestoreOriginalFrame = nil;
	self.lhRepetitions = nil;
	self.lhDelayPerUnit = nil;
	self.lhLoop = nil;
	self.lhAnimAtStart = nil;
	self.repetitionsPerformed = nil;
	self.time = nil;
	self.currentFrame = nil;
	self.paused = nil;
	self.elapsedFrameTime = nil;
	self.lastEventTime = nil;

	for i = 1, #self.lhFrames do
		self.lhFrames[i]:removeSelf();
		self.lhFrames[i] = nil;
	end
	self.lhFrames = nil;


	self = nil
end
--------------------------------------------------------------------------------
function LHAnimationNode:addEnterFrameEvent()
	self:addEventListener(Event.ENTER_FRAME, self.enterFrame, self)
end
--------------------------------------------------------------------------------
function LHAnimationNode:removeEnterFrameEvent()
	self:removeEventListener(Event.ENTER_FRAME, self.enterFrame, self)
end
--------------------------------------------------------------------------------
function LHAnimationNode:animationTime()

	local totalTime = 0.0
	for i=1, #self.lhFrames do
		local frmInfo = self.lhFrames[i];
		totalTime = totalTime + frmInfo.lhDelayPerUnit*self.lhDelayPerUnit;
	end
	return totalTime
end
--------------------------------------------------------------------------------
function LHAnimationNode:enterFrame( event )
        
    if(self == nil)then
	    return;
    end
       
    if(self.paused)then
    	return;
    end 	
        	
    if(self.coronaSprite == nil)then
    	print("ERROR: animation node is not valid as it does not have an associated sprite");
	    return;
    end
    if(self.lastEventTime == -1)then
    	self.lastEventTime = event.time;
    	return;
    end
    	
    local dT = event.time - self.lastEventTime;
    self.lastEventTime = event.time;
	self.elapsedFrameTime = self.elapsedFrameTime + dT;
    
	--print("enter frame " .. self.lhUniqueName .. " time " .. tostring(event.time) .. " " .. (dT));
	
	local frmObject = self.lhFrames[self.currentFrame];
	
	if(frmObject == nil)then
		return;
	end
	
	if(frmObject.lhDelayPerUnit*self.lhDelayPerUnit <= self.elapsedFrameTime)then
	
	--print("enters here");
		self.elapsedFrameTime = 0.0;
		self.previousFrame = self.currentFrame;
	
		self.currentFrame = self.currentFrame + 1;
		
		if(self.currentFrame > #self.lhFrames)then
		
			--we should trigger a notification that the animation has ended
            local endedEvent = Event.new(LHAnimationHasEndedGlobalNotification)
            endedEvent.object = self.coronaSprite;
            endedEvent.name = LHAnimationHasEndedGlobalNotification;
            stage:dispatchEvent(endedEvent)


			local endedPerSprEvent = Event.new(LHAnimationHasEndedPerSpriteNotification)
            endedPerSprEvent.object = self.coronaSprite;
            endedPerSprEvent.name = LHAnimationHasEndedPerSpriteNotification;
            self.coronaSprite:dispatchEvent(endedPerSprEvent)

			if(self.lhLoop)then
				self.currentFrame = 1
			else
				self.repetitionsPerformed = self.repetitionsPerformed +1
				
				if(self.repetitionsPerformed >= self.lhRepetitions)then
				
					self.paused = true;
					self.currentFrame = #self.lhFrames
					
					--restore original frame is handled by stopAnimation
					--we should remove the animation object from the sprite
					self:stopAnimation();
					return;
				else
					self.currentFrame = 1
				end
			end			
		end
		
		
		local activeFrame = self.lhFrames[self.currentFrame];

		--print("prev frame " .. (self.previousFrame) .. " cur frame " .. (self.currentFrame));

		self.coronaSprite:removeChild(self.lhFrames[self.previousFrame].giderosSpriteFrame);
		self.coronaSprite:addChild(activeFrame.giderosSpriteFrame);
			
		
		--check if this frame has any info and trigger a notification if it has
		--		if([[[activeFrame notifications] allKeys] count] > 0){
		--[[
		local endedEvent = { name=LHAnimationFrameGlobalNotification, 
							 object = self.coronaSprite, 
							 userInfo = activeFrame.lhNotifications:tableWithKeysAndObjects() } 
		self:dispatchEvent(endedEvent);

		local endedEventPerSpr = { name=LHAnimationFramePerSpriteNotification, 
							 object = self.coronaSprite, 
							 userInfo = activeFrame.lhNotifications:tableWithKeysAndObjects() } 
		self.coronaSprite:dispatchEvent(endedEventPerSpr);
		--]]			
	end      
end
--------------------------------------------------------------------------------
function LHAnimationNode:setCurrentFrame(frmNo)

   if (self.lhFrames ~= nil) then -- << It's getting here with lhFrames as nil
      if(frmNo > 0 and frmNo <=  #self.lhFrames)then
         self.currentFrame = frmNo;
      end
      
      if self.coronaSprite:contains(self.lhFrames[self.previousFrame].giderosSpriteFrame)then
         self.coronaSprite:removeChild(self.lhFrames[self.previousFrame].giderosSpriteFrame);
      end    
      self.coronaSprite:addChild(self.lhFrames[self.currentFrame].giderosSpriteFrame);
   end
end
--------------------------------------------------------------------------------
function LHAnimationNode:spriteFrameAtIndex(frmNo)
	if(frmNo > 0 and frmNo <=  #self.lhFrames)then
		return self.lhFrames[frmNo].giderosSpriteFrame;
	end
	return nil;
end
--------------------------------------------------------------------------------
function LHAnimationNode:stopAnimation()
	self.paused = true;
	
	-- check for restore original frame and restore it
	self.currentFrame = 1;
	if(self.lhRestoreOriginalFrame)then
		--self.coronaSprite:setFrame(1);
        
        if self.coronaSprite:contains(self.lhFrames[self.previousFrame].giderosSpriteFrame)then
            self.coronaSprite:removeChild(self.lhFrames[self.previousFrame].giderosSpriteFrame);
        end
        self.coronaSprite:addChild(self.lhFrames[1].giderosSpriteFrame);
	end
	
	--on corona we dont remove the animations because maybe the player wants 
	--to play it later - we remove anim when sprite is removed
	--self:removeSelf();
end
function LHAnimationNode:prepare()
	--print("prepare animation " .. self.lhUniqueName);
    if self.coronaSprite:contains(self.lhFrames[self.previousFrame].giderosSpriteFrame)then
    	self.coronaSprite:removeChild(self.lhFrames[self.previousFrame].giderosSpriteFrame);
    end


	self.currentFrame = 1;
	self.previousFrame = 1;
	self.coronaSprite:addChild(self.lhFrames[self.currentFrame].giderosSpriteFrame);
end
